/*
 * Copyright 2009 Johnson Consulting Services
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * 
 */
package com.johnsoncs.gwt.widgets.samples.client;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.johnsoncs.gwt.application.client.model.Data;
import com.johnsoncs.gwt.application.client.model.Model;
import com.johnsoncs.gwt.application.client.model.QueryPath;
import com.johnsoncs.gwt.application.client.model.SimpleModelDefinition;
import com.johnsoncs.gwt.application.client.validation.ValidationContext;
import com.johnsoncs.gwt.application.client.validation.ValidationState;
import com.johnsoncs.gwt.application.client.validation.Validator;
import com.johnsoncs.gwt.application.client.validation.ValidatorBuilder;
import com.johnsoncs.gwt.application.client.validation.impl.ModelContext;
import com.johnsoncs.gwt.application.client.validation.impl.ValidationTrigger;
import com.johnsoncs.gwt.widgets.client.util.Callback;

/**
 * @author wilj
 *
 */
public class ValidationDemo extends Composite {
	private class DemoValidatorBuilder extends ValidatorBuilder {
		public DemoValidatorBuilder(final ValidationContext context) {
			super(context);
		}

		/* (non-Javadoc)
		 * @see com.johnsoncs.gwt.application.client.validation.ValidatorBuilder#defineConstraints()
		 */
		@Override
		protected void defineConstraints() {
			// TODO need to work out property bindings correctly so that ranges can be tested on types like Integer and Date
			// TODO add support for Data.size() on range operations
			define("myObject.someField").required().length(2, 4);
			define("myObject.someArray.*.abbrev").required().length(2, 2).between("aa", "zz");
			define("myObject.someArray.*.title").length(10, 10);
			define("myObject.blah.someField").length(3, null);
		}

	}

	private final VerticalPanel panel = new VerticalPanel();
	private final FlexTable table = new FlexTable();
	private final HTML allMessages = new HTML();
	private final Model model = defineModel();
	private final ValidationContext context = new ModelContext(model);
	private final Validator validator = new DemoValidatorBuilder(context).build();

	private final Map<String, Label> labels = new HashMap<String, Label>();

	private final ModelTree tree = new ModelTree(model);

	public ValidationDemo() {
		panel.add(table);
		panel.add(tree);
		panel.add(allMessages);
		super.initWidget(panel);

		validator.addValidationCallback(new Callback<List<ValidationState>>() {
			@Override
			public void exec(final List<ValidationState> value) {
				for (final Label lbl : labels.values()) {
					lbl.setText("");
				}
				for (final ValidationState v : value) {
					final Label lbl = labels.get(v.getPath().toString());
					if (lbl != null) {
						String s = lbl.getText();
						final String msg = v.getMessage() + " " + v.getParameters().toString();
						if (s.isEmpty()) {
							s = msg;
						} else {
							s += " & " + msg;
						}
						lbl.setText(s);
					}
				}
				tree.refresh();
				showAllValidationResults(value);
			}
		});

		addField("myObject.someField", "test");
		addField("myObject.someArray.0.abbrev", "");
		addField("myObject.someArray.0.title", "");
		addField("myObject.someArray.1.abbrev", "");
		addField("myObject.someArray.1.title", "");
		addField("myObject.blah.someField", "");

	}

	private void addField(final String path, final String defaultText) {
		final TextBox text = new TextBox();
		final QueryPath q = QueryPath.parse(path);
		final Label label = new Label();

		labels.put(path, label);
		model.set(q, defaultText);
		text.setValue(defaultText);
		text.addValueChangeHandler(new ValueChangeHandler<String>() {
			@Override
			public void onValueChange(final ValueChangeEvent<String> event) {
				model.set(q, text.getValue());
			}
		});

		ValidationTrigger.bind(validator, text);

		final int row = table.getRowCount();
		table.setWidget(row, 0, text);
		table.setWidget(row, 1, label);
	}

	/**
	 * @return
	 */
	private Model defineModel() {
		final SimpleModelDefinition def = new SimpleModelDefinition();
		def.define("myObject", "com.johnsoncs.MyClass");
		def.define("myObject.someArray.*", "com.johnsoncs.MyArrayOfStuff");
		def.define("myObject.blah", "com.johnsoncs.Blah");
		return new Model(def, new Data());
	}

	private void showAllValidationResults(final List<ValidationState> results) {
		final StringBuilder sb = new StringBuilder("<b>All validation results:</b><pre>");
		for (final ValidationState v : results) {
			sb.append(v.getPath().toString());
			sb.append(" ");
			sb.append(v.getMessage());
			sb.append(" ");
			sb.append(v.getParameters().toString());
			sb.append("\n");
		}
		sb.append("</pre>");
		allMessages.setHTML(sb.toString());
	}
}
